# 调用backtrader引擎，仅兼容历史数据
# 6系列策略为框架实例策略，用作教学
from enum import Enum
from core.object import Interval
from core.constant import *
from core.template import BacktestingTemplate
from model.model1.factor.factor_am import ArrayManagerFactor


class Symbol(Enum):
    DDQ = Model.DefaultSymbol.value
    # DDQ = "600519.SH"
    # ZSYH = "600036.SH"


class P(Enum):
    # 结构参数
    cash = 100000
    shortcash = False
    commission = 0.001
    am_size = 60
    symbols = [mem.value for mem in Symbol]
    # intervals = [Interval.MINUTE, Interval.MINUTE5, Interval.MINUTE15]  # 策略需要的所有K线周期
    intervals = [Interval.MINUTE]  # 策略需要的所有K线周期
    interval = Interval.MINUTE  # 原始回测数据的K线周期
    # 策略参数
    wide_wave_period = 240


class DDQStrategy(BacktestingTemplate):
    def __init__(self, p_dc):
        super().__init__(p_dc)
        # - 长周期变量数值变量
        self.wide_wave_period = P.wide_wave_period.value
        self.wide_wave_index = 0
        self.optimal_price = 0
        self.stop_loss_point = 0
        # - 长周期变量条件变量
        self.fast_move_cond = 0  # 快速变化条件
        self.wide_wave_cond = 0  # 宽幅波动条件
        self.boll_extreme_cond = False  # 布林带极端条件
        # - 短周期条件变量
        self.atr_cond = False  # atr值条件
        self.touch_stop_cond = False  # 触及止损偏离点条件

    def on_full(self):
        index = self.index
        value = self.value
        size = self.size_dc[Symbol.DDQ.value]
        price = self.price_dc[Symbol.DDQ.value]
        qty = self.qty_dc[Symbol.DDQ.value]

        am_1: ArrayManagerFactor = self.am_container.get(Symbol.DDQ.value, Interval.MINUTE)
        close = am_1.close[-1]
        # if index % 200 == 0:
        #     print(f"索引：{index}，标的：{am_1.symbol}，周期：{am_1.interval}，时间：{am_1.datetime}，收盘价：{close}")
        # - 仓位判断前
        # 宽幅波动条件，关注宽幅波动条件到期索引
        self.wide_wave_cond = am_1.wide_wave(n=60)  # close在区间内90%时间位于sma21一侧，启动宽幅波动周期标记
        if self.wide_wave_cond in [1, -1]:
            self.wide_wave_index = index + self.wide_wave_period

        # - 仓位判断时
        if size == 0:
            # 快速变动条件
            self.fast_move_cond = am_1.fast_change(n=3, border=0.00)  # 连续5k，close，sma7关系一致，且累计变动大于x

            # atr值条件
            c_atr = am_1.c_atr(array=False)
            self.atr_cond = True if c_atr > 0.65 else False

            # - 订单条件
            # -- 买单条件
            buy_cond = True if self.fast_move_cond == 1 and index <= self.wide_wave_index and self.atr_cond else False
            # -- 卖单条件
            sell_cond = True if self.fast_move_cond == -1 and index <= self.wide_wave_index and self.atr_cond else False
            if buy_cond:
                self.buy(Symbol.DDQ.value, size=1)
                self.optimal_price = close
                self.stop_loss_point = 10*am_1.atr(array=False)
            elif sell_cond:
                self.sell(Symbol.DDQ.value, size=1)
                self.optimal_price = close
                self.stop_loss_point = 10*am_1.atr(array=False)

        elif size > 0:
            # 更新最优价
            self.optimal_price = close if close > self.optimal_price else self.optimal_price
            # 布林带极端条件
            boll_std = am_1.std(n=20, array=False)
            signal_std = am_1.std(n=14, array=False)
            self.boll_extreme_cond = True if signal_std > 1.18 * boll_std else False
            # 触及止损偏离点
            self.touch_stop_cond = True if close < self.optimal_price - self.stop_loss_point and index > self.wide_wave_index else False
            # - 买单平仓条件
            if self.touch_stop_cond:
                self.close()

        elif size < 0:
            # 更新最优价
            self.optimal_price = close if close < self.optimal_price else self.optimal_price
            # 布林带极端条件
            boll_std = am_1.std(n=20, array=False)
            signal_std = am_1.std(n=14, array=False)
            self.boll_extreme_cond = True if signal_std > 1.18 * boll_std else False
            # 触及止损偏离点
            self.touch_stop_cond = True if close > self.optimal_price + self.stop_loss_point and index > self.wide_wave_index else False
            # - 卖单平仓条件
            if self.touch_stop_cond:
                self.close()

        # 仓位判断后

    pass






